<?php
/* 
 AUTH_OK, AUTH_FAIL, AUTH_PERM, AUTH_NONE relate to page level authorization
 $this->_authorized relates to whether the person has supplied a valid username / password combination
/* Must supply connected Database Class $db */ 
 
/**************************************************
 * Minimum Database Scheme for Authorization Class 
CREATE TABLE users (
  id smallint(5) unsigned NOT NULL auto_increment,
  sess_id varchar(16) NOT NULL default '',
  group_id tinyint(3) unsigned NOT NULL default '0',
  fullname varchar(60) NOT NULL default '',
  username varchar(16) NOT NULL default '',
  password varchar(16) NOT NULL default '',
  email varchar(60) NOT NULL default '',
  account enum('active','disabled') NOT NULL default 'active',
  logins mediumint(8) unsigned NOT NULL default '0',
  last_login datetime NOT NULL default '0000-00-00 00:00:00',
  last_ip varchar(15) NOT NULL default '',
  modified timestamp(14) NOT NULL,
  created datetime NOT NULL default '0000-00-00 00:00:00',
  PRIMARY KEY  (id),
  UNIQUE KEY sess_id (sess_id,username)
) TYPE=InnoDB;
 
CREATE TABLE groups (
  id tinyint(3) unsigned NOT NULL auto_increment,
  level tinyint(3) unsigned NOT NULL default '0',
  name varchar(16) NOT NULL default '',
  created datetime NOT NULL default '0000-00-00 00:00:00',
  modified timestamp(14) NOT NULL,
  PRIMARY KEY  (id)
) TYPE=InnoDB;
 */ 
if ( !defined('AUTH_CODE_IMAGE_FILE') ) {
        define('AUTH_CODE_IMAGE_FILE', '/auth_code.php');
}
if ( !defined('AUTH_CODE_ENABLE') ) {
        define('AUTH_CODE_ENABLE', false);
}
if ( AUTH_CODE_ENABLE == true ) {
        define('SESSION_CODE', true);
}
require_once('Framework.class.php');
require_once('Capshaw.class.php');

abstract class AuthenticatedFramework extends Framework {

	//Handle standard authenicated request
	abstract protected function handleAuthenticatedRequest();
	abstract protected function handleNotAuthenticatedRequest();
	abstract protected function handleLogout();
	abstract protected function handleLogin();

	final public function __construct(array $init, array $params) {
		parent::__construct($init, $params);
	}

	//-------------------------------------------------

	final protected function handleRequest() {
		if ( isset($_GET['capshaw']) ) {
			Capshaw::draw(self::getVar('auth_code'));
			exit;
		} elseif ( strlen(self::getVar('auth_code')) == 0 ) {
			//Generate New AuthCode if needed
			self::generateAuthCode();
		}
	
		if ( self::handleAuthorization() ) {
			$this->handleAuthenticatedRequest();
			return;
		}
		$this->handleNotAuthenticatedRequest();
		return;
	}

	//-------------------------------------------------

	protected function isAuthenticated() {
		return self::getVar('authenicated');
	}

	//-------------------------------------------------
	/**
	 * This function is called to authorize a user. Developer is free
	 * to create any authorization method
	 * Returns AUTH_OK	      Authentication OK
	 *	 AUTH_PERMISSION      Authentication succeeded but insufficient permission
	 *	 AUTH_FAILIED	 Authentication failed
	 *	 AUTH_PUBLIC	  Page viewable by public
	 */
	protected function authorize($permission, $user, $groupid) {
		list($authtype,$authperm) = split(":",strtolower($permission)); 

		if ( $authperm == 'public' ) {
			return AUTH_PUBLIC;

		} elseif ( $authtype == 'user') {
			if ( $user == $authperm ) {
				return AUTH_OK;
			}

		} elseif ( $authtype == 'group' ) {
			$results = self::db()->select("SELECT level FROM groups 
							WHERE name = '{$authperm}'");
			if ( $results->get_numrows() == 1 ) {
				list($auth_groupid) = $results->get_row();
				if ( $group >= $auth_groupid ) {
					return AUTH_OK;
				}
			}

		} else {
			Log::warn('Invalid authtype supplied: ' . $authtype);
			return AUTH_PERMISSION;
		}
		return AUTH_PERMISSION;
	}

	//-------------------------------------------------

	protected function authenicate($username, $password, $auth_code) {
		//Match code if using CODE AUTH
		if ( strtoupper($auth_code) == self::getVar('auth_code') ) {

			//Check username and password are not empty	
			if ( $username != '' && $password != '' ) {
				$username = addslashes($username);
				$password = addslashes($password);	

				$sql = "SELECT users.id as user_id,
						users.last_login as last_login,
						users.last_ip as last_ip,
						users.group_id as group_id,
						groups.level as level,
						groups.name as group_name 
				     	FROM users JOIN groups ON users.group_id = groups.id
        		               	WHERE users.username = '{$username}' 
					AND users.password = PASSWORD('{$password}') 
					AND users.account = 'active'";

				$results = self::db()->select($sql);

				$auth = $results->getRowAssoc();
				if ( $auth ) {
					//User Authorization OK 
			
					//Update login information	
					$update = "UPDATE users 
						   SET  logins = logins + 1,
							last_login=NOW(),
							last_ip='{$_SERVER['REMOTE_ADDR']}' 
						   WHERE id = {$auth['user_id']}";
					self::db()->update($update);

					//Register variable
					self::register('auth_username',	$username); 
					self::register('auth_userid',	$auth['user_id']); 
					self::register('auth_level',	$auth['level']); 
					self::register('auth_groupid',	$auth['group_id']); 
					self::register('auth_groupname',$auth['group_name']); 
					self::register('last_ip', 	$auth['last_ip']);
					self::register('last_login', 	$auth['last_login']); 
					self::register('authenicated', 	true);
					return true;

				} else {
					//User Authorization failed
					self::register("auth_username",$username); 
					$this->_authenicated = false;
					return false;
				}
			}
		}
		self::generateAuthCode();
		self::register('auth_username', $username); 
		self::register('authenicated', false);
		return false;
	}

	//-------------------------------------------------

	private function handleAuthorization() {
		Log::debug('calling Framework::handleAuthorization');

		if ( !self::isAuthenticated() ) {
			Log::debug('User not authenticated');
			//Not Authenticated
			if( $_SERVER['REQUEST_METHOD'] == 'POST' ) {
				if ( self::authenicate($_POST['auth_user'],
						 $_POST['auth_pass'],
						 $_POST['auth_code']) ) {
					Log::info('User ' . $_POST['auth_user'] . ' authenicated');
					//$this->handleLogin();
				} else {
					Log::info('AUTH_FAILED');
					self::setParameter('AUTH_STATUS', 'FAILED');
					self::setParameter('AUTH_MESSASGE', AUTH_FAILED_MESSAGE);
					self::setParameter('AUTH', 'framework/auth_form.html');
					return false;
				}
			} else {
				Log::info('AUTH_NONE');
				self::setParameter('AUTH_STATUS', 'NONE');
				self::setParameter('AUTH_MESSASGE', '');
				self::setParameter('AUTH', 'framework/auth_form.html');
				return false;
			}
		}
	
		$result = self::authorize(self::getInitialization('AUTHORIZATION'),
					   self::getVar('auth_username'),
					   self::getVar('auth_groupid'));
		switch($result) {
		case AUTH_OK:
			Log::info('AUTH_OK');
			self::setParameter('AUTH_STATUS', 'OK');
			self::setParameter('AUTH_MESSASGE', AUTH_OK_MESSAGE);
			self::setParameter('AUTH', 'framework/auth_ok.html');
			return true;

		case AUTH_PUBLIC:
			Log::info('AUTH_PUBLIC');
			self::setParameter('AUTH_STATUS', 'PUBLIC');
			self::setParameter('AUTH_MESSASGE', '');
			self::setParameter('AUTH', 'framework/auth_ok.html');
			return true;

		case AUTH_PERM:
		default:
			Log::info('AUTH_PERM');
			self::setParameter('AUTH_STATUS', 'PERMISSION');
			self::setParameter('AUTH_MESSASGE', AUTH_PERMISSION_MESSAGE);
			self::setParameter('AUTH', 'framework/auth_perm.html');
			return false;
		}
		return false;
	}

	//-------------------------------------------------

	private function generateAuthCode() {
		$code = CAPSHAW_LENGTH;
	
		for( $i=0; $i < strlen($code); $i++ ) {
			$c = mt_rand( 0, 35);

			if ( $c >= 0 && $c <= 9 ) {
				$c += 48; 
			} else {
				$c += 55;
			}
			$code{$i} = chr( $c ); 
		}
		Log::debug("AuthCode: $code");
		self::register('auth_code', $code);
	}
}

?>
